﻿using CaseManagerLibrary.Log;
using NetSDKCS;
using PSDLib.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace PSDLib.Download
{
    public class HKDownloadServer : IDownloadServer
    {
        public string ID { get; set; }
        public string Name { get; set; }
        public ILog Logger { get; set; }
        public string ServerIP { get; set; }
        public int ServerPort { get; set; }
        public string ServerUser { get; set; }
        public string ServerPassword { get; set; }

        private bool online = false;
        private static object lock_online = new object();

        public bool Online
        {
            get
            {
                lock (lock_online)
                {
                    return online;
                }
            }
            set
            {
                lock (lock_online)
                {
                    online = value;
                }
            }
        }

        public event EventHandler OnDisConnect;
        public event EventHandler OnReConnect;

        private bool m_bInitSDK = false;
        private int m_LoginID = -1;
        private uint iLastErr = 0;
        private HKNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo;
        public HKNetSDK.NET_DVR_IPPARACFG_V40 m_struIpParaCfgV40;
        public HKNetSDK.NET_DVR_GET_STREAM_UNION m_unionGetStream;
        public HKNetSDK.NET_DVR_IPCHANINFO m_struChanInfo;
        private uint dwAChanTotalNum = 0;
        private uint dwDChanTotalNum = 0;
        List<ChannelInfo> channelList = new List<ChannelInfo>();

        private bool resetting = false;



        public HKDownloadServer()
        {
            Logger = new ConsoleLog();
            Logger.BringToFront = false;
        }

        public void Cleanup()
        {

        }

        public string GetLastError()
        {
            return HKNetSDK.NET_DVR_GetLastError().ToString();
        }

        public bool Init()
        {
            m_bInitSDK = false;

            try
            {
                m_bInitSDK = HKNetSDK.NET_DVR_Init();

                if (m_bInitSDK)
                {
                    Logger.Info("【" + Name + "】初始化HK SDK成功");
                }
                else
                {
                    Logger.Error("【" + Name + "】初始化HK SDK失败");
                }
            }
            catch (Exception ex)
            {
                Logger.Error("【" + Name + "】初始化HK SDK失败：" + ex.Message);
            }

            return m_bInitSDK;
        }

        public bool Login()
        {
            bool success = false;

            m_LoginID = HKNetSDK.NET_DVR_Login_V30(ServerIP, ServerPort, ServerUser, ServerPassword, ref DeviceInfo);

            if (m_LoginID < 0)
            {
                Online = false;
                iLastErr = HKNetSDK.NET_DVR_GetLastError();
                Logger.Error("NET_DVR_Login_V30 failed, error code= " + iLastErr); //登录失败，输出错误号
                success = false;
            }
            else
            {
                //登录成功
                Online = true;
                success = true;
                Logger.Info("登录存储设备成功");
            }

            return success;
        }

        public void Logout()
        {
            try
            {
                if (m_LoginID > 0)
                {
                    bool result = HKNetSDK.NET_DVR_Logout(m_LoginID);
                    if (result)
                    {
                        m_LoginID = -1;
                        Logger.Info("登出存储设备：" + result.ToString());
                    }
                    else
                    {
                        iLastErr = HKNetSDK.NET_DVR_GetLastError();
                        Logger.Error("登出存储设备：" + result.ToString() + " NET_DVR_Logout failed, error code= " + iLastErr);
                    }
                }
            }
            catch { }
            finally
            {
                Online = false;
            }
        }

        public bool ReLogin()
        {
            bool success = false;

            resetting = true;

            Cleanup();

            if (Init())
            {
                success = Login();
            }
            else
            {
                success = false;
            }

            resetting = false;

            return success;
        }

        public IDownloader CreateDownload(dl_files file)
        {
            //创建海康存储设备下载器
            var hk_downloader = new HK_NVR_Downloader();
            hk_downloader.m_LoginID = m_LoginID;
            hk_downloader.Id = file.id;
            hk_downloader.Logger = Logger;
            hk_downloader.DownloadServer = this;

            return hk_downloader;
        }

        public void ResetSessionInfo(IDownloader downloader)
        {
            if (downloader != null)
            {
                downloader.ResetSessionInfo(m_LoginID);
            }
        }

        public void InfoIPChannel()
        {
            uint dwSize = (uint)Marshal.SizeOf(m_struIpParaCfgV40);

            IntPtr ptrIpParaCfgV40 = Marshal.AllocHGlobal((Int32)dwSize);
            Marshal.StructureToPtr(m_struIpParaCfgV40, ptrIpParaCfgV40, false);

            uint dwReturn = 0;
            int iGroupNo = 0; //该Demo仅获取第一组64个通道，如果设备IP通道大于64路，需要按组号0~i多次调用NET_DVR_GET_IPPARACFG_V40获取
            if (!HKNetSDK.NET_DVR_GetDVRConfig(m_LoginID, HKNetSDK.NET_DVR_GET_IPPARACFG_V40, iGroupNo, ptrIpParaCfgV40, dwSize, ref dwReturn))
            {
                //获取IP资源配置信息失败，输出错误号
                Logger.Error("NET_DVR_GET_IPPARACFG_V40 failed, error code= " + HKNetSDK.NET_DVR_GetLastError());
            }
            else
            {
                // succ
                m_struIpParaCfgV40 = (HKNetSDK.NET_DVR_IPPARACFG_V40)Marshal.PtrToStructure(ptrIpParaCfgV40, typeof(HKNetSDK.NET_DVR_IPPARACFG_V40));

                byte byStreamType;
                uint iDChanNum = 64;

                if (dwDChanTotalNum < 64)
                {
                    iDChanNum = dwDChanTotalNum; //如果设备IP通道小于64路，按实际路数获取
                }

                for (int i = 0; i < iDChanNum; i++)
                {
                    byStreamType = m_struIpParaCfgV40.struStreamMode[i].byGetStreamType;
                    m_unionGetStream = m_struIpParaCfgV40.struStreamMode[i].uGetStream;

                    switch (byStreamType)
                    {
                        //目前NVR仅支持0- 直接从设备取流一种方式
                        case 0:
                            dwSize = (uint)Marshal.SizeOf(m_unionGetStream);
                            IntPtr ptrChanInfo = Marshal.AllocHGlobal((Int32)dwSize);
                            Marshal.StructureToPtr(m_unionGetStream, ptrChanInfo, false);
                            m_struChanInfo = (HKNetSDK.NET_DVR_IPCHANINFO)Marshal.PtrToStructure(ptrChanInfo, typeof(HKNetSDK.NET_DVR_IPCHANINFO));
                            //列出IP通道
                            if (m_struChanInfo.byEnable != 0 && m_struChanInfo.byIPID != 0)
                            {
                                var ch = new ChannelInfo();
                                ch.Id = (i + (int)m_struIpParaCfgV40.dwStartDChan).ToString();
                                ch.Name = ch.Id;
                                channelList.Add(ch);
                            }

                            Marshal.FreeHGlobal(ptrChanInfo);
                            break;

                        default:
                            break;
                    }
                }
            }
            Marshal.FreeHGlobal(ptrIpParaCfgV40);
        }

        public List<ChannelInfo> GetChannelList()
        {
            channelList.Clear();

            if (online)
            {
                dwAChanTotalNum = (uint)DeviceInfo.byChanNum;
                dwDChanTotalNum = (uint)DeviceInfo.byIPChanNum + 256 * (uint)DeviceInfo.byHighDChanNum;

                if (dwDChanTotalNum > 0)
                {
                    //数字通道
                    InfoIPChannel();
                }
                else
                {
                    //模拟通道
                    for (int i = 0; i < dwAChanTotalNum; i++)
                    {
                        var ch = new ChannelInfo();
                        ch.Id = (i + (int)DeviceInfo.byStartChan).ToString();
                        ch.Name = ch.Id;
                        channelList.Add(ch);
                    }
                }
            }

            return channelList;
        }
    }
}
